package gupao.concurrency.stream;

import lombok.AllArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

@Slf4j
public class SimpleStreamSample {

    public static void main(String[] args) {
        System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8");
        List<Person> list = mock();
        warm(list);
        log.info("there are {} persons ", list.size());
        long start = System.currentTimeMillis();
        Map<Long, Person> largeThan16PersonMap = filterMinAgePersonMap(list, 16);
        log.info("there are {} persons large than age 16. Time Cost: {}ms", largeThan16PersonMap.size(), (System.currentTimeMillis() - start));
        start = System.currentTimeMillis();
        largeThan16PersonMap = parallelFilterMinAgePersonMap(list, 16);
        log.info("there are {} persons large than age 16. Time Cost: {}ms", largeThan16PersonMap.size(), (System.currentTimeMillis() - start));
        compareAvg(list);
    }

    static void compareAvg(List<Person> list){
        long start = System.currentTimeMillis();
        double avgAge1 = avgAge(list);
        log.info("{} person, avg age: {}, time cost: {}ms", list.size(), avgAge1, (System.currentTimeMillis() - start));

        start = System.currentTimeMillis();
        double avgAge2 = parallelAvgAge(list);
        log.info("{} person, avg age: {}, time cost: {}ms", list.size(), avgAge2, (System.currentTimeMillis() - start));
    }

    static double avgAge(List<Person> personList){
        return personList.stream().mapToInt(p -> p.age).average().getAsDouble();
    }

    static Map<Long, Person> filterMinAgePersonMap(List<Person> personList, int minAge){
        return personList.stream().filter(p -> p.age >= minAge ).collect(Collectors.toMap(p -> p.id, p -> p));
    }

    static double parallelAvgAge(List<Person> personList){
        return personList.parallelStream().mapToInt(p -> p.age).average().getAsDouble();
    }

    static Map<Long, Person> parallelFilterMinAgePersonMap(List<Person> personList, int minAge){
        return personList.parallelStream()
                .filter(p -> p.age >= minAge ).collect(Collectors.toMap(p -> p.id, p -> p));
    }

    static void warm(List<Person> list){
        log.info("warm");
        filterMinAgePersonMap(list, 16);
        parallelFilterMinAgePersonMap(list, 16);
    }



    static List<Person> mock(){
        Random r = new Random();
        List<Person> list = new ArrayList<>();
        for(int i = 0; i < 30000000; i++){
            list.add(new Person(i+1L, r.nextInt(45)));
        }
        return list;
    }

    @AllArgsConstructor
    @ToString
    static class Person{
        Long id;
        int age;
    }
}
